
#include <stdint.h>
#include <stdlib.h>
#include <Utility.h>
#include <HID/HIDiClass.h>
#include <HID/SIM.h>
#include <HID/command.h>
#include "tag_type.h"
#include "simple_protocol.h"
#include "Debug.h"
#include <Log.h>
#include <Reader/ReaderHidHF.h>
#include <Reader/ReaderHidBLE.h>


static int ICLASS_Active(void){
	int ret = 0;
	
	if(reader.hidState != 2){
		Reader_HID_HF_ResetRF();
		ret = Reader_HID_HF_PowerOnSE();
		if(ret){
			LOG_E("Reader_HID_HF_PowerOnSE: %d", ret);
			return -1;
		}
		reader.hidState = 1;
		ret = Reader_HID_HF_SetupSE();
		if(ret){
			LOG_E("Reader_HID_HF_SetupSE: %d", ret);
			return -1;
		}
		reader.hidState = 2;
	}
	
	return ret;
}

static void ICLASS_ResponsePAC(buffer_t* response, uint8_t bitCount, uint8_t len, uint8_t pac[]){
	LOG_B("report:", pac, len, 8);
	net_buf_simple_add_u8(response, bitCount); //bit count
	net_buf_simple_add_u8(response, len); //id length
	net_buf_simple_add_mem(response, pac, len); //id length
}



static int api_ICLASS_GetPACBits(buffer_t* command, buffer_t* response){
	uint8_t len;
	uint8_t* pac = net_buf_simple_tail(response);
	int ret;
	if(reader.bleFlags & 1){
		ret = rhb_get_pacs(pac, &len);
	}
	else{
		ret = Reader_HID_HF_GetPACBits(pac, &len);
	}
	API_CHECK(ret);
	
	LOG_B("pac:", pac, len, 8);
	uint8_t bit_count = (len-1) * 8;
	uint8_t pad = pac[0];
	uint8_t uid_bit = bit_count - pad;
	response->data++;
	net_buf_simple_add(response, len - 1);
	net_buf_simple_push_u8(response, len - 1); //id length
	net_buf_simple_push_u8(response, uid_bit); //bit count
	LOG_B("report:", response->data, response->len, 8);
	return ERR_NONE;
}


/*--------------------------------------------------------------------------------------------------*/
//	
/*
Command: [1101][Byte: Book][Byte: Page]
Response: [00][Bool: Result][Byte Array(8): ConfigBlock]
*/
#if 1
int Reader_HID_HF_PowerOnSE(void);

int Reader_HID_HF_SetupSE(void);


static int api_ICLASS_SelectPage	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Book;
		uint8_t Page;
	}SelectPage_param_t;
	SelectPage_param_t* param = (SelectPage_param_t*)command->data;
	LOG_D("book=%d, page=%d", param->Book, param->Page);
	int ret = ICLASS_Active();
	API_CHECK(ret);
	uint8_t config [8];
	ret = IClass_Select(param->Book, param->Page, config);
	API_CHECK(ret);
	net_buf_simple_add_mem(response, config, 8); //ConfigBlock
	return ERR_NONE;
}
#endif 
/*--------------------------------------------------------------------------------------------------*/
//	
/*
1.5.16.3. ICLASS_Authenticate
Command: [1102][Byte Array(3): KeyReferenceOID][Byte: KeyType]
Response: [00][Bool: Result]
*/
static int api_ICLASS_Authenticate	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t KeyReferenceOID[3];
		uint8_t KeyType;
	}Authenticate_param_t;
	Authenticate_param_t* param = (Authenticate_param_t*)command->data;
	uint8_t *oid = param->KeyReferenceOID;
	LOG_D("KeyReferenceOID=%02X%02X%02X, KeyType=%d", oid[0], oid[1], oid[2], param->KeyType);
	int ret = ICLASS_Active();
	API_CHECK(ret);
	ret = IClass_Auth(param->KeyType, oid+1);
	API_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	
/*
1.5.16.4. ICLASS_ReadBlock
Command: [1103][Byte: Block]
Response: [00][Bool: Result][Byte Array(8): BlockData]
*/
static int api_ICLASS_ReadBlock	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Block;
	}ReadBlock_param_t;
	ReadBlock_param_t* param = (ReadBlock_param_t*)command->data;
	LOG_D("Block=%d", param->Block);
	int ret = ICLASS_Active();
	API_CHECK(ret);
	ret = IClass_Read(param->Block, response->data);
	API_CHECK(ret);
	net_buf_simple_add(response, 8);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	
/*
1.5.16.5. ICLASS_WriteBlock
Command: [1104][Byte: Block][Byte Array(8): BlockData]
Response: [00][Bool: Result]
*/
static int api_ICLASS_WriteBlock	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Block;
		uint8_t BlockData[8];
	}WriteBlock_param_t;
	WriteBlock_param_t* param = (WriteBlock_param_t*)command->data;
	LOG_D("Block=%d", param->Block);
	LOG_B("Data ", param->BlockData, 8, 8);
	int ret = ICLASS_Active();
	API_CHECK(ret);
	ret = IClass_Write(param->Block, param->BlockData);
	API_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//	
/*
ICLASS_RollKey
Command: [1111][Byte Array(3): KeyReferenceOID][Byte Array(3): PreviousKeyRefOID][Byte: KeyType]
Response: [00][Bool: Result]
*/
static int api_ICLASS_RollKey	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t KeyReferenceOID[3];
		uint8_t PreviousKeyRefOID[3];
		uint8_t KeyType;
	}RollKey_param_t;
	RollKey_param_t* param = (RollKey_param_t*)command->data;
	LOGD("KeyType", "%d", param->KeyType);
	LOG_SBUF("KeyReferenceOID", param->KeyReferenceOID, sizeof(param->KeyReferenceOID));
	LOG_SBUF("PreviousKeyRefOID", param->PreviousKeyRefOID, sizeof(param->PreviousKeyRefOID));
	int ret = ICLASS_Active();
	API_CHECK(ret);
	ret = IClass_RollKey(param->KeyType, param->PreviousKeyRefOID+1, param->KeyReferenceOID+1);
	API_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
//Seos
/*--------------------------------------------------------------------------------------------------*/

/*
Seos_Select
Command: [1120]
Response: [00][Bool: Result][Byte Array(Var): FCI]
*/
static int api_Seos_Select(buffer_t* command, buffer_t* response){
	int ret;
	TRACE_I("enter");
	//SE模块上电
	ret = Reader_HID_HF_PowerOnSE();
	if(ret){
		LOG_E("PowerOnSE fail: %d", ret);
		return ret;
	}
	//把卡信息发给SE
	ret = Reader_HID_HF_SetupSE();
	if(ret){
		LOG_E("SetupSE fail: %d", ret);
		return ret;
	}
	uint8_t fciLen;
	ret = Reader_HID_Seos_Select(response->data, &fciLen);
	API_CHECK(ret);
	LOG_SBUF("FCI", response->data, fciLen);
	net_buf_simple_add(response, fciLen);
	net_buf_simple_push_u8(response, fciLen);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/

/*
Seos_Authenticate
Command: [1121][Byte Array(3): ENC KeyOID][Byte Array(3): MAC KeyOID][Byte Array(3): Auth KeyOID][Byte Array(Var): AFD OID]
Response: [00][Bool: Result]
*/
static int api_Seos_Authenticate(buffer_t* command, buffer_t* response){
	TRACE_I("enter");

	typedef struct __PACKED  {
		uint8_t ENC[3];
		uint8_t MAC[3];
		uint8_t Auth[3];
		uint8_t adfLen;
		uint8_t adf[];
	}Seos_Authenticate_param_t;
	int ret;
	Seos_Authenticate_param_t* param = (Seos_Authenticate_param_t*)command->data;
	LOG_SBUF("ENC", param->ENC, sizeof(param->ENC));
	LOG_SBUF("MAC", param->MAC, sizeof(param->MAC));
	LOG_SBUF("Auth", param->Auth, sizeof(param->Auth));
	LOG_SBUF("adf", param->adf, param->adfLen);
	ret = Reader_HID_Seos_Authenticate(param->adf, param->adfLen, param->ENC, param->MAC, param->Auth);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/

/*
Seos_GetData
Command: [1122][Byte: ReadLen][Byte Array(Var): Tag]
Response: [00][Bool: Result][Byte Array(Var): Data]
*/

static int api_Seos_GetData(buffer_t* command, buffer_t* response){
	TRACE_I("enter");
	typedef struct __PACKED  {
		uint8_t readLen;
		uint8_t tagLen;
		uint8_t tag[];
	}Seos_GetData_param_t;
	int ret;
	Seos_GetData_param_t* param = (Seos_GetData_param_t*)command->data;
	LOGD("readLen", "%d", param->readLen);
	LOG_SBUF("tag", param->tag, param->tagLen);
	uint8_t ilen = 0;
	ret = Reader_HID_Seos_GetData(param->tagLen, param->tag, param->readLen, response->data, &ilen);
	API_CHECK(ret);
	LOG_SBUF("data", response->data, ilen);
	net_buf_simple_add(response, ilen);
	net_buf_simple_push_u8(response, ilen);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/

/*
Seos_PutData
Command: [1123][Byte Array(Var): Tag][Byte Array(Var): Data]
Response: [00][Bool: Result]
*/
typedef struct __PACKED  {
	uint8_t TagLen;
	uint8_t* Tag;
	uint8_t DataLen;
	uint8_t* Data;
}Seos_PutData_param_t;

static void Seos_Get_PutData_param(buffer_t* command, Seos_PutData_param_t *param){
	param->TagLen = net_buf_simple_pull_u8(command);
	param->Tag = net_buf_simple_pull_mem(command, param->TagLen);
	param->DataLen = net_buf_simple_pull_u8(command);
	param->Data = net_buf_simple_pull_mem(command, param->DataLen);
}

static int api_Seos_PutData(buffer_t* command, buffer_t* response){
	TRACE_I("enter");
	int ret;
	Seos_PutData_param_t param;
	Seos_Get_PutData_param(command, &param);
	LOG_SBUF("Tag", param.Tag, param.TagLen);
	LOG_SBUF("Data", param.Data, param.DataLen);
	ret = Reader_HID_Seos_PutData(param.TagLen, param.Tag,  param.DataLen, param.Data);
	API_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
/*
GatherCardInfo
Command: [1124]
Response: [00][Bool: Result][Byte: Cipher][Byte: Hash][Byte Array(Var): Diversifier]
*/

static int api_Seos_GatherCardInfo(buffer_t* command, buffer_t* response){
	int ret;
	uint8_t cipher, hash;
	uint8_t diversifierLength;
	ret = Reader_HID_Seos_GatherCardInfo(response->data, &diversifierLength, &cipher, &hash);
	API_CHECK(ret);
	LOG_SBUF("diversifier", response->data, diversifierLength);
	LOGD("cipher", "%d", cipher);
	LOGD("hash", "%d", hash);
	net_buf_simple_add(response, diversifierLength);
	net_buf_simple_push_u8(response, diversifierLength);
	net_buf_simple_push_u8(response, hash);
	net_buf_simple_push_u8(response, cipher);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
/*
Seos_WritePrivacyKey
Command: [1125][Byte: Cipher][Byte Array(Var): Tag][Byte Array(Var): Data]
Response: [00][Bool: Result]
*/

typedef struct {
	uint8_t Cipher;
	uint8_t EncKeyLen;
	uint8_t* EncKey;
	uint8_t MacKeyLen;
	uint8_t* MacKey;
}Seos_WritePrivacyKey_param_t;

static void Seos_Get_WritePrivacyKey_param(buffer_t* command, Seos_WritePrivacyKey_param_t *param){
	param->Cipher = net_buf_simple_pull_u8(command);
	param->EncKeyLen = net_buf_simple_pull_u8(command);
	param->EncKey = net_buf_simple_pull_mem(command, param->EncKeyLen);
	param->MacKeyLen = net_buf_simple_pull_u8(command);
	param->MacKey = net_buf_simple_pull_mem(command, param->MacKeyLen);
}

static int api_Seos_WritePrivacyKey(buffer_t* command, buffer_t* response){
	int ret;
	Seos_WritePrivacyKey_param_t param;
	Seos_Get_WritePrivacyKey_param(command, &param);
	LOGD("Cipher", "%d", param.Cipher);
	LOG_SBUF("EncKey", param.EncKey, param.EncKeyLen);
	LOG_SBUF("MacKey", param.MacKey, param.MacKeyLen);
	ret = Reader_HID_Seos_WritePrivacyKey(param.Cipher, param.EncKey, param.EncKeyLen, param.MacKey, param.MacKeyLen);
	API_CHECK(ret);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
/*
Seos_ChangeAuthKey
Command: [1126][Byte: Cipher][Byte: Hash][Byte Array(16): AuthKey][Byte Array(Var): Diversifier][Byte Array(Var): Adf]
Response: [00][Bool: Result]
*/

typedef struct {
	uint8_t Cipher;
	uint8_t Hash;
	uint8_t *AuthKey;//[16]
	uint8_t DiversifierLen;
	uint8_t* Diversifier;
	uint8_t AdfLen;
	uint8_t* Adf;
}Seos_ChangeAuthKey_param_t;

static void Seos_Get_ChangeAuthKey_param(buffer_t* command, Seos_ChangeAuthKey_param_t *param){
	param->Cipher = net_buf_simple_pull_u8(command);
	param->Hash = net_buf_simple_pull_u8(command);
	param->AuthKey = net_buf_simple_pull_mem(command, 16);
	param->DiversifierLen = net_buf_simple_pull_u8(command);
	param->Diversifier = net_buf_simple_pull_mem(command, param->DiversifierLen);
	param->AdfLen = net_buf_simple_pull_u8(command);
	param->Adf = net_buf_simple_pull_mem(command, param->AdfLen);
}

static int api_Seos_ChangeAuthKey(buffer_t* command, buffer_t* response){
	int ret;
	Seos_ChangeAuthKey_param_t param;
	Seos_Get_ChangeAuthKey_param(command, &param);
	LOGD(NULL, "Cipher=%d, Hash=%d", param.Cipher, param.Hash);
	LOG_SBUF("AuthKey", param.AuthKey, 16);
	LOG_SBUF("Diversifier", param.Diversifier, param.DiversifierLen);
	LOG_SBUF("Adf", param.Adf, param.AdfLen);
	ret = Reader_HID_Seos_ChangeAuthKey(param.AuthKey, param.Adf, param.AdfLen, 
		param.Diversifier, param.DiversifierLen, param.Cipher, param.Hash);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/
/*
SE_LoadKey
Command: [1110][Byte: IsPersistent][Byte Array(3): KeyOID][Byte Array(Var): Key]
Response: [00][Bool: Result]
*/

static int api_SE_LoadKey(buffer_t* command, buffer_t* response){
	int ret;
	typedef struct __PACKED  {
		uint8_t IsPersistent;
		uint8_t keyOID[3];
		uint8_t keyLen;
		uint8_t key[];
	}Sam_LoadKey_param_t;
	Sam_LoadKey_param_t * param = (Sam_LoadKey_param_t*)command->data;
	LOGD("IsPersistent", "%d", param->IsPersistent);
	LOG_SBUF("keyOID", param->keyOID, sizeof(param->keyOID));
	LOG_SBUF("key", param->key, param->keyLen);
	ret = SamCommand_LoadKey(param->IsPersistent, param->keyOID, param->keyLen, param->key, NULL, NULL);
	API_CHECK(ret);
	return ERR_NONE;
}

/*--------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------*/

enum ClassCardType{
	CardType_Unknown = 0,						//未知
	CardType_2K_iCLASS_2K_2 = 1,				//2K/2
	CardType_16K_iCLASS_16K_16 = 2,				//16K/16
	CardType_16K_iCLASS_16K_2 = 3,				//16K/2
	CardType_32K_iCLASS_16K_16_plus_16K_1 = 4,	//32K Book0=16K/16, Book1=16K/1
	CardType_32K_iCLASS_16K_2_plus_16K_1 = 5,	//32K Book0=16K/2, Book1=16K/1
	CardType_32K_iCLASS_Book1_16K_1 = 6,		//32K Book0未知，Book1=16K/1
};

static uint8_t ICLASS_GetCardType(const uint8_t data[8]){
	uint16_t memCfg = (uint16_t)(data[4] << 8) | data[5];
	
	switch(memCfg){
	case 0x7F1F:
	case 0xF91F: return CardType_2K_iCLASS_2K_2;				//2K/2
	case 0xF99F: return CardType_16K_iCLASS_16K_2;				//16K/2
	case 0xE91F: return CardType_16K_iCLASS_16K_16;				//16K/16
	case 0xE9FF: return CardType_32K_iCLASS_16K_2_plus_16K_1;	//32K 16K/2+16K/1
	case 0xE97F: return CardType_32K_iCLASS_16K_16_plus_16K_1;	//32K 16K/16 + 16K/1
	case 0xE97B: return CardType_32K_iCLASS_Book1_16K_1;		//32K Book1_16K/1
	}
	
	return CardType_Unknown;
}

static int api_ICLASS_GetAttr(buffer_t* command, buffer_t* response){
	uint8_t block = 1;
	uint8_t data[8];
	int ret = ICLASS_Active();
	API_CHECK(ret);
	ret = IClass_Read(block, data);
	API_CHECK(ret);
	LOG_D("Block=%d", block);
	LOG_D("Data[4&5] = %02X%02X", data[4], data[5]);
	uint8_t type = ICLASS_GetCardType(data);
	net_buf_simple_add_u8(response, type);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------*/
#if 0
/*--------------------------------------------------------------------------------------------------*/
static int api_ICLASS_ProcessAdminKey(buffer_t* command, buffer_t* response){
	SIM_SetWaitTime(11 + (1 << 4) * 960*20, 11 + (1 << 13)*40);
	int ret = Reader_HID_HF_ProcessAdminKey();
	API_CHECK(ret);
	SIM_SetWaitTime(11 + (1 << 4) * 960*2, 11 + (1 << 13)*4);
	return ERR_NONE;
}
/*--------------------------------------------------------------------------------------------------*/
static int api_ICLASS_ProcessConfigCard(buffer_t* command, buffer_t* response){
	SIM_SetWaitTime(11 + (1 << 4) * 960*20, 11 + (1 << 13)*40);
	int ret = Reader_HID_HF_ProcessConfigCard();
	API_CHECK(ret);
	SIM_SetWaitTime(11 + (1 << 4) * 960*2, 11 + (1 << 13)*4);
	return ERR_NONE;
}
#endif 
/*--------------------------------------------------------------------------------------------------*/

static const api_entry_t api_iclass_list[5] = {
	[0] = api_ICLASS_GetPACBits,
	[1] = api_ICLASS_SelectPage,
	[2] = api_ICLASS_Authenticate,
	[3] = api_ICLASS_ReadBlock,
	[4] = api_ICLASS_WriteBlock,
};
	
/*--------------------------------------------------------------------------------------------------*/
static int api_SE_Active	(buffer_t* command, buffer_t* response){
	uint8_t * atr = response->data;
	uint8_t alen = 0;
	int ret = SIM_PowerOn(atr, &alen);
	API_CHECK(ret);
	SIM_SetWaitTime(11 + (1 << 4) * 960*100, 11 + (1 << 13)*20);
	net_buf_simple_add(response, alen);
	return ERR_NONE;
}

static int api_SE_ExchangeAPDU	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint16_t CLen;
		uint8_t CAPDU[];
	}ExchangeAPDU_param_t;
	ExchangeAPDU_param_t* param = (ExchangeAPDU_param_t*)command->data;
	LOG_TIME();
	LOG_SBUF("CAPDU", param->CAPDU, param->CLen);
	uint16_t rlen;
	int ret = SIM_Exchange(param->CAPDU, param->CLen, response->data, &rlen);
	LOG_TIME();
	API_CHECK(ret);
	net_buf_simple_add(response, rlen);
	LOG_SBUF("RAPDU", response->data, rlen);
	return ERR_NONE;
}

static int api_SE_PowerOff	(buffer_t* command, buffer_t* response){
	SIM_PowerOff();
	return ERR_NONE;
}

static int api_SE_GetVersion	(buffer_t* command, buffer_t* response){
	uint8_t len = 0;
	int ret = IClass_GetSEVersion(response->data, &len);
	API_CHECK(ret);
	net_buf_simple_add(response, len);
	return ERR_NONE;
}

static const api_entry_t api_se_list[4] = {
	[0] = api_SE_Active,
	[1] = api_SE_ExchangeAPDU,
	[2] = api_SE_PowerOff,
	[3] = api_SE_GetVersion,
};
/*--------------------------------------------------------------------------------------------------*/

static const api_func_t api_hid_card_func[] = {
	{.func = 0x20, api_Seos_Select},
	{.func = 0x21, api_Seos_Authenticate},
	{.func = 0x22, api_Seos_GetData},
	{.func = 0x23, api_Seos_PutData},
	{.func = 0x24, api_Seos_GatherCardInfo},
	{.func = 0x25, api_Seos_WritePrivacyKey},
	{.func = 0x26, api_Seos_ChangeAuthKey},

	{.func = 0x10, api_SE_LoadKey},
	{.func = 0x11, api_ICLASS_RollKey},
	
	{.func = 0xFF, api_ICLASS_GetAttr},
};


static int iclass_call_api(buffer_t* command, buffer_t* response){
	const uint8_t iclass_num = sizeof(api_iclass_list)/sizeof(api_iclass_list[0]);
	uint8_t fun = net_buf_simple_pull_u8(command);
	
	if(fun < iclass_num){
		if(api_iclass_list[fun]){
			return api_iclass_list[fun](command, response);
		}
		return ERR_UNKNOWN_FUNCTION;
	}

	//rdy 定义指令
	if(0x80 <= fun && fun <= 0x8F){
		fun -= 0x80;
		const uint8_t se_num = sizeof(api_se_list)/sizeof(api_se_list[0]);
		if(fun < se_num){
			if(api_se_list[fun]){
				return api_se_list[fun](command, response);
			}
			return ERR_UNKNOWN_FUNCTION;
		}
	}
	const uint8_t fun_num = sizeof(api_hid_card_func)/sizeof(api_hid_card_func[0]);
	return protocol_call_fun(fun, api_hid_card_func, fun_num, command, response);
}

static int iclass_api(buffer_t* command, buffer_t* response){
	int ret = iclass_call_api(command, response);
	if(ret > 0){
		return ret;
	}
	protocol_response_result(response, ret);
	return ERR_NONE;
}

SIMPLE_API_DEFINE(API_CLASS_ICLASS, iclass_api);


